package com.wh1200.mybatis.xmlless.util

import cn.hutool.core.util.ReflectUtil
import java.lang.reflect.AnnotatedElement
import kotlin.reflect.KProperty
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.jvm.javaField

/**
 * Created by 吴昊 on 2018/12/24.
 */
object AnnotationUtil {

  fun hasAnnotation(element: AnnotatedElement, clazz: String): Boolean {
    return element.hasAnyAnnotation(clazz)
  }

  fun getAnnotation(element: AnnotatedElement, clazz: String): Annotation? {
    return element.getAnnotation(clazz)
  }

  inline fun <reified T : Annotation> resolve(parameter: AnnotatedElement): T? {
    return when (parameter) {
      is KProperty<*> -> resolveFromProperty(parameter)
      else            -> parameter.getAnnotation(T::class.java)
    }
  }

  inline fun <reified T : Annotation> resolveFromProperty(parameter: KProperty<*>): T? {
    return parameter.findAnnotation() ?: parameter.javaField?.getDeclaredAnnotation(T::class.java)
  }

  fun <T> getAnnotationFieldValue(
      parameter: AnnotatedElement, annotationClass: String,
      property: String
  ): T? {
    val anno = parameter.getAnnotation(annotationClass) ?: return null
    return anno.getAnnotationFieldValue(property)
  }

  fun <T> getAnnotationFieldValue(anno: Annotation, property: String): T {
    return anno.getAnnotationFieldValue(property)
  }

}



internal fun AnnotatedElement.hasAnnotation(clazz: String): Boolean {
  return this.annotations.any {
    it.annotationClass.qualifiedName == clazz
  }
}

internal fun <T> Annotation.getAnnotationFieldValue(property: String): T {
  val method = ReflectUtil.getMethodOfObj(this, property, *arrayOfNulls<Any>(0))
  return ReflectUtil.invoke(this, method, *arrayOfNulls<Any>(0))
}

internal fun AnnotatedElement.getAnnotation(clazz: String): Annotation? {
  return this.annotations.find {
    it.annotationClass.qualifiedName == clazz
  }
}

internal fun AnnotatedElement.hasAnyAnnotation(vararg annotations: String): Boolean {
  return this.annotations.any { it.annotationClass.qualifiedName in annotations }
}
